home *** CD-ROM | disk | FTP | other *** search
- #include <exec/types.h>
- #include "defs.h"
-
- static char rcsid [] = "$Id: pagehandler.c,v 3.9 95/12/16 18:36:40 Martin_Apel Exp $";
-
- /***********************************************************************/
-
- PRIVATE ULONG OrigRootTableContents [NUM_PTR_TABLES];
- extern ULONG RootTableContents [NUM_PTR_TABLES];
- PRIVATE void *ResetHandlerData;
- PRIVATE UWORD ResetSignal;
- PRIVATE BOOL RootTableModified;
-
- #define MIN(a,b) ((a)<(b)?(a):(b))
-
-
- PRIVATE int InitPagetables (void)
-
- /* Physical addresses have to be used. Later the physical address of
- * the allocated chunk is used. For now (68040.library does an identical
- * mapping) we use logical addresses.
- */
-
- {
- ULONG *FirstPage;
- int i;
- int rc;
-
- NewList (&FrameList);
- NewList (&FrameAllocList);
-
- for (i = 0; i < NUM_PTR_TABLES; i++)
- {
- RootTableContents [i] =
- OrigRootTableContents [i] = *(RootTable + ROOTINDEX (VirtAddrStart) + i);
- *(RootTable + ROOTINDEX (VirtAddrStart) + i) = BUILD_DESCR (LOCUNUSED,
- PAGED_OUT, PT_TABLE);
- }
-
- RootTableModified = TRUE;
-
- if ((FirstPage = AllocAligned (PAGESIZE, MEMF_PUBLIC | MEMF_REVERSE,
- PAGEALIGN, 0L)) == NULL)
- {
- PRINT_DEB ("Couldn't allocate first frame", 0L);
- return (ERR_NOT_ENOUGH_MEM);
- }
-
- if ((rc = MarkAddress (VirtAddrStart, PAGESIZE, CACHE_MODE | PAGE_RESIDENT,
- (ULONG)FirstPage, FALSE)) != SUCCESS)
- {
- FreeMem (FirstPage, PAGESIZE);
- return (rc);
- }
-
- if ((rc = MarkAddress (VirtAddrStart + PAGESIZE,
- (ULONG)MIN (VirtAddrEnd - (VirtAddrStart + PAGESIZE), PartSize),
- BUILD_DESCR (LOCUNUSED, PAGED_OUT, 0), 0L, FALSE)) != SUCCESS)
- return (rc);
-
- PRINT_DEB ("Pointer and page table initialized", 0L);
-
- /* Allocate misc page frames */
-
- for (i = 0; i < CurrentConfig.MinMem / PAGESIZE; i++)
- {
- if (!AddFrame (0L))
- {
- PRINT_DEB ("Couldn't allocate %ld bytes", CurrentConfig.MinMem);
- return (ERR_NOT_ENOUGH_MEM);
- }
- }
-
- PRINT_DEB ("Frames allocated", 0L);
-
- CacheClearU ();
- (*PFlushA) ();
-
- return (SUCCESS);
- }
-
- /*********************************************************************/
-
- PRIVATE void ResetHandler (void)
-
- {
- PRINT_DEB ("Sending reset signal to pagehandler", 0L);
- Signal (PageHandlerTask, 1L << ResetSignal);
-
- if (IsA3000)
- {
- UBYTE *ForceReset = (UBYTE*)0xde0002;
-
- *ForceReset &= ~0x80;
- }
-
- /* The following seems to cause a GURU 80000038 upon reset on A3000's and
- * sometimes a GURU 8000000b on A4000's.
- * On a A3000 without this the machine hung upon reset. Now enabled only for A3000
- */
-
- if (IsA3000)
- RestoreMMUState30 ();
- }
-
- /*********************************************************************/
-
- PRIVATE int InitPageHandler (void)
-
- {
- ULONG *VectorTable;
- int rc;
-
- /* 16 signals per task are guaranteed, so the following three lines
- * can't fail
- */
-
- PageFaultSignal = AllocSignal (-1L);
- PageHandlerQuitSignal = AllocSignal (-1L);
- ResetSignal = AllocSignal (-1L);
-
- ResetInProgress = FALSE;
-
- if ((PageHandlerPort = CreateMsgPort ()) == NULL)
- return (ERR_NOT_ENOUGH_MEM);
-
- NumTables = 0;
-
- if ((rc = OpenPageFile ()) != SUCCESS)
- {
- PRINT_DEB ("InitPageHandler: Couldn't open paging file", 0L);
- return (rc);
- }
-
- PRINT_DEB ("Paging file opened", 0L);
-
- PartSize = ALIGN_DOWN (PartSize, PAGESIZE);
-
- if ((rc = InitPagetables ()) != SUCCESS)
- return (rc);
-
- PRINT_DEB ("Page tables initialized", 0L);
-
- if ((rc = InitCache ()) != SUCCESS)
- {
- PRINT_DEB ("Couldn't init cache", 0L);
- return (rc);
- }
-
- if ((ResetHandlerData = InstallResetHandler (ResetHandler, -32L)) == NULL)
- PRINT_DEB ("Couldn't install reset handler", 0L);
-
- Forbid ();
- VectorTable = (ULONG*)ReadVBR ();
- OrigTrapHandler = (void (*) ()) *(VectorTable + 2);
-
- PRINT_DEB("VBR=%08lx",(ULONG)VectorTable);
-
- switch (ProcessorType)
- {
- case PROC_68060: *(VectorTable + 2) = (ULONG)&TrapHandler60;
- break;
- case PROC_68040: *(VectorTable + 2) = (ULONG)&TrapHandler40;
- break;
- case PROC_68851:
- case PROC_68030: *(VectorTable + 2) = (ULONG)&TrapHandler30;
- break;
- #ifdef DEBUG
- default:
- PRINT_DEB ("InitPageHandler: Unknown processor type", 0L);
- ColdReboot ();
- #endif
- }
-
- CacheClearU ();
- Permit ();
- PRINT_DEB ("Trap-Vector set", 0L);
-
- return (SUCCESS);
- }
-
- /***********************************************************************/
-
- PRIVATE void Cleanup_PageHandler (void)
-
- {
- ULONG *VectorTable;
- int i;
-
- if (OrigTrapHandler != NULL)
- {
- Forbid ();
- VectorTable = (ULONG*)ReadVBR ();
- *(VectorTable + 2) = (ULONG) OrigTrapHandler;
- CacheClearU ();
- Permit ();
- }
-
- PRINT_DEB ("Before killing pointer tables", 0L);
-
- if (RootTableModified)
- {
- for (i = ROOTINDEX (VirtAddrStart);
- i < ROOTINDEX (VirtAddrStart) + NUM_PTR_TABLES; i++)
- {
- if (TABLE_RESIDENT_P (*(RootTable + i)))
- {
- if (KillPointerTable ((ULONG*)ALIGN_DOWN (*(RootTable + i), POINTERTABALIGN),
- TRUE))
- {
- MarkPage (*(RootTable + i), CACHEABLE);
- *(RootTable + i) = OrigRootTableContents [i - ROOTINDEX (VirtAddrStart)];
- }
- }
- }
-
- CacheClearU ();
- (*PFlushA) ();
- }
-
- PRINT_DEB ("Removing reset handler", 0L);
- RemoveResetHandler (ResetHandlerData);
-
- PRINT_DEB ("Killing map", 0L);
-
- KillCache ();
-
- if (PartSize != 0)
- ClosePageFile ();
-
- PRINT_DEB ("Page file closed", 0L);
-
- RemAllFrames ();
-
- PRINT_DEB ("All frames freed", 0L);
-
- if (PageHandlerPort != NULL)
- DeleteMsgPort (PageHandlerPort);
-
- FreeSignal ((ULONG)PageFaultSignal);
- FreeSignal ((ULONG)PageHandlerQuitSignal);
- FreeSignal ((ULONG)ResetSignal);
- }
-
- /***********************************************************************/
-
- PRIVATE BOOL LockResidentPage (ULONG Page)
-
- /* Tries to lock a page in memory, if it is already resident.
- * It can only lock it if there are still unlocked pages in memory.
- * This has to be handled asynchroneously.
- */
- {
- ULONG *root_entry,
- *pointer_entry,
- *page_entry;
-
- PRINT_DEB ("Received lock msg for address %lx", Page);
-
- root_entry = RootTable + ROOTINDEX (Page);
- pointer_entry = (ULONG*)ALIGN_DOWN (*root_entry, POINTERTABALIGN) +
- POINTERINDEX (Page);
- if (TABLE_INVALID_P (*pointer_entry))
- {
- PRINT_DEB ("Couldn't lock page", 0L);
- return (FALSE);
- }
-
- page_entry = (ULONG*)ALIGN_DOWN (*pointer_entry, PAGETABALIGN) +
- PAGEINDEX (Page);
-
- Forbid ();
-
- if (PAGE_RESIDENT_P (*page_entry))
- {
- if (!LOCKED_P (*page_entry))
- {
- if ((NumLocked + NumTables + 5 > NumPageFrames) && !AddFrame (0L))
- {
- Permit ();
- PRINT_DEB ("Couldn't lock page. NumLocked = %ld", NumLocked);
- return (FALSE);
- }
-
- PRINT_DEB ("Locking resident page %lx", Page);
- NumLocked++;
- *page_entry |= LOCKED;
- (*PFlushP) (Page);
- }
- Permit ();
- return (TRUE);
- }
-
- Permit ();
- return (FALSE);
- }
-
- /***********************************************************************/
-
- PRIVATE void LockPage (ULONG Page)
-
- {
- if (LockResidentPage (Page))
- {
- ThisPageLocked = TRUE;
- Signal ((struct Task*)VM_ManagerProcess, 1L << LockAckSignal);
- }
- else
- {
- struct TrapStruct *LockFault;
-
- Forbid ();
- if ((LockFault = (struct TrapStruct*)RemHead (&Free)) == NULL)
- {
- Permit ();
- ThisPageLocked = FALSE;
- Signal ((struct Task*)VM_ManagerProcess, 1L << LockAckSignal);
- return;
- }
-
- Permit ();
- LockFault->FaultTask = (struct Task*)LOCK_TASK;
- LockFault->FaultAddress = Page;
- AddPageReq (LockFault);
- SetSignal (1L << PageFaultSignal, 1L << PageFaultSignal);
- }
- }
-
- /***********************************************************************/
-
- PRIVATE void UnlockAllPages (void)
-
- {
- struct FrameDescr *tmp_fd;
-
- for (tmp_fd = (struct FrameDescr*)FrameList.lh_Head;
- tmp_fd->FDNode.mln_Succ != NULL;
- tmp_fd = (struct FrameDescr*) tmp_fd->FDNode.mln_Succ)
- {
- if ((tmp_fd->PageType == PT_PAGE) && LOCKED_P (*(tmp_fd->PageDescr)))
- {
- Forbid ();
- *(tmp_fd->PageDescr) &= ~LOCKED;
- (*PFlushP) (tmp_fd->LogAddr);
- Permit ();
- }
- }
-
- NumLocked = 0;
- }
-
- /***********************************************************************/
-
- PRIVATE void FreePages (ULONG Start, ULONG Size)
-
- {
- ULONG start_page,
- end_page,
- tmp,
- *desc;
-
- struct FrameDescr *cur,
- *succ;
-
- /*
- PRINT_DEB ("Received FreePageReq for address %lx", Start);
- PRINT_DEB (" size %ld", Size);
- */
- start_page = ALIGN_UP(Start, PAGESIZE);
- end_page = ALIGN_DOWN (Start + Size, PAGESIZE);
-
- /* Two passes have to be made: First for all the non-resident pages.
- * For them the corresponding swap page is freed.
- * The second pass loops through all pages frames, marking those as
- * unused which lie within the given address range.
- */
-
- /* First pass */
-
- tmp = start_page;
- while (tmp < end_page)
- {
- desc = (ULONG*)ALIGN_DOWN (*(RootTable + ROOTINDEX (tmp)), POINTERTABALIGN);
- desc = desc + POINTERINDEX (tmp);
-
- if (TABLE_INVALID_P (*desc))
- {
- tmp += PAGES_PER_TABLE * PAGESIZE;
- continue;
- }
-
- desc = (ULONG*)ALIGN_DOWN (*desc, PAGETABALIGN) + PAGEINDEX (tmp);
- tmp += PAGESIZE;
- if (PAGE_RESIDENT_P (*desc))
- continue; /* Not interested in resident pages in this pass */
-
- if (STATE_FROM_DESCR(*desc) == COMING_IN)
- continue;
-
- Forbid ();
- if (PGNUM_FROM_DESCR (*desc) != LOCUNUSED)
- {
- FreePageOnDisk (PGNUM_FROM_DESCR (*desc));
- *desc = BUILD_DESCR (LOCUNUSED, PAGED_OUT, PT_PAGE);
- (*PFlushP) (tmp-PAGESIZE);
- }
- Permit ();
- }
-
- /* Second pass */
-
- /* Because cur might be removed at the end of the loop,
- * its successor is stored at the start of each looping
- */
-
- end_page -= PAGESIZE;
- for (cur = (struct FrameDescr*)FrameList.lh_Head,
- succ = (struct FrameDescr*)cur->FDNode.mln_Succ;
- cur->FDNode.mln_Succ != NULL;
- cur = succ, succ = (struct FrameDescr*)cur->FDNode.mln_Succ)
- {
- if ((cur->PageType == PT_PAGE) &&
- (cur->LogAddr >= start_page) && (cur->LogAddr <= end_page))
- {
- Forbid ();
- *(cur->PageDescr) &= ~(USED | MODIFIED);
- (*PFlushP) (cur->LogAddr);
- Permit ();
- cur->Modified = FALSE;
- if (cur->PageNumOnDisk != LOCUNUSED)
- {
- FreePageOnDisk (cur->PageNumOnDisk);
- cur->PageNumOnDisk = LOCUNUSED;
- }
- Remove ((struct Node*)cur);
- AddHead (&FrameList, (struct Node*)cur);
- }
- }
- }
-
- /***********************************************************************/
-
- PRIVATE void NewConfigReceived (void)
-
- {
- PRINT_DEB ("New config received", 0L);
-
- if (NumPageFrames * PAGESIZE < CurrentConfig.MinMem)
- {
- /* There's memory missing */
- int total_frames;
-
- PRINT_DEB ("Adding mem until %ld bytes", CurrentConfig.MinMem);
- total_frames = CurrentConfig.MinMem / PAGESIZE;
- while ((NumPageFrames < total_frames) && AddFrame (0L));
- }
- else if (NumPageFrames * PAGESIZE > CurrentConfig.MaxMem)
- {
- struct TrapStruct *DummyTrap;
-
- PRINT_DEB ("Removing mem until %ld bytes", CurrentConfig.MaxMem);
- /* Fool the pagehandler by simulating a low memory condition.
- * InformTask has to handle this as a special case.
- */
- Forbid ();
- DummyTrap = (struct TrapStruct*)RemHead (&Free);
- Permit ();
- if (DummyTrap == NULL)
- return;
- DummyTrap->FaultAddress = NULL; /* Marker for remove */
- DummyTrap->RemFrameFlags = MEMF_ANY;
- DummyTrap->FaultTask = (struct Task*)REDUCE_TASK;
- AddPageReq (DummyTrap);
- LowMem++;
- SetSignal (1L << PageFaultSignal, 1L << PageFaultSignal);
- }
- }
-
- /***********************************************************************/
-
- PRIVATE void HandleVMMsg (void)
-
- {
- struct VMMsg *VMMsg;
-
- while ((VMMsg = (struct VMMsg*)GetMsg (PageHandlerPort)) != NULL)
- {
- switch (VMMsg->VMCommand)
- {
- case VMCMD_LockPage:
- LockPage (VMMsg->PageAddress);
- break;
-
- case VMCMD_UnlockAllPages:
- UnlockAllPages ();
- break;
-
- case VMCMD_FreePages:
- /* PRINT_DEB ("FreeRequest from task", 0L);
- PRINT_DEB (VMMsg->VMSender->tc_Node.ln_Name, 0L);
- */
- FreePages (VMMsg->FreeAddress, VMMsg->FreeSize);
- break;
-
- case VMCMD_NewConfig:
- NewConfigReceived ();
- break;
-
- case VMCMD_NewWriteBuffer:
- PRINT_DEB ("Received new write buffer. Size: %ld", VMMsg->NewWriteBufferSize);
- NewCache (VMMsg->NewWriteBuffer, VMMsg->NewWriteBufferSize);
- break;
-
- default: PRINT_DEB ("Received unknown msg type", (ULONG)VMMsg->VMCommand);
- }
- if (VMMsg->ReplySignal != NULL)
- Signal (VMMsg->VMSender, 1L << VMMsg->ReplySignal);
- else
- FreeMem (VMMsg, sizeof (struct VMMsg));
- }
- }
-
- /***********************************************************************/
-
- void PageHandler (void)
-
- {
- ULONG ReceivedSignals;
- ULONG WaitMask;
- struct VMMsg *InitMsg;
- int rc;
- BOOL quit = FALSE;
-
- if ((rc = InitPageHandler ()) != SUCCESS)
- {
- PRINT_DEB ("Init failed", 0L);
- InitError (rc);
- Cleanup_PageHandler ();
- Signal ((struct Task*)VM_ManagerProcess, 1L << InitPort->mp_SigBit);
- return;
- }
-
- /* Tell VM_Manager that the page handler has been initialized correctly */
- if ((InitMsg = DoOrigAllocMem (sizeof (struct VMMsg), MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
- {
- PRINT_DEB ("Not enough memory for init msg", 0L);
- Cleanup_PageHandler ();
- Signal ((struct Task*)VM_ManagerProcess, 1L << InitPort->mp_SigBit);
- return;
- }
-
- InitMsg->VMSender = FindTask (NULL);
- InitMsg->VMCommand = VMCMD_InitReady;
- InitMsg->ReplySignal = NULL; /* VM_Manager should free this */
- PutMsg (InitPort, (struct Message*)InitMsg);
-
- WaitMask = (1L << PageFaultSignal) |
- (1L << PageHandlerQuitSignal) |
- (1L << ReplySignal) |
- (1L << PageHandlerPort->mp_SigBit) |
- (1L << ResetSignal);
-
- while (!quit)
- {
- /* PRINT_DEB ("Waiting for signals", 0L); */
- ReceivedSignals = Wait (WaitMask);
- /* PRINT_DEB ("Received signals %lx", ReceivedSignals); */
-
- if (ReceivedSignals & (1L << PageFaultSignal))
- {
- /* PRINT_DEB ("Received page fault signal", 0L); */
- HandlePageFault ();
- }
-
- if (ReceivedSignals & (1L << ReplySignal))
- {
- /* handle return from paging device.
- * Page has been either written out or read in.
- */
- /* PRINT_DEB ("Received return signal", 0L); */
- HandleReturn ();
- CheckWaitingFaults ();
- }
-
- if (ReceivedSignals & (1L << PageHandlerPort->mp_SigBit))
- {
- /* PRINT_DEB ("VMMsg received", 0L); */
- HandleVMMsg ();
- }
-
- if (ReceivedSignals & (1L << PageHandlerQuitSignal))
- {
- PRINT_DEB ("Received quit signal", 0L);
- quit = TRUE;
- }
-
- if (ReceivedSignals & (1L << ResetSignal))
- {
- PRINT_DEB ("Received ResetSignal", 0L);
- PRINT_DEB ("PagefaultsInProgress = %ld", (LONG)PageFaultsInProgress);
- ResetInProgress = TRUE;
- }
-
- if (ResetInProgress && PageFaultsInProgress == 0)
- {
- if (CurrentConfig.PageDev == PD_FILE)
- {
- PRINT_DEB ("Waiting 2 seconds", 0L);
- Delay (100L); /* Wait 2 seconds for the fs to calm down */
- }
- PRINT_DEB ("No pagefaults in progress. Ready for reset", 0L);
- PRINT_DEB ("Allowing reset", 0L);
- ResetHandlerDone (ResetHandlerData);
- }
- }
-
- Cleanup_PageHandler ();
- PRINT_DEB ("Exiting", 0L);
- }
-